<?php
/*
 *	The Request class provides many methods for examining the HTTP request.
 */
class Request{

	/**
	 * @var string
	 */
	static $_pathInfo	= null;

	/**
	 * @var string
	 */
	static $_requestUri	= null;

	/**
	 * @var string
	 */
	static $_scriptUrl	= null;

	/**
	 * @var string
	 */
	static $_baseUrl	= null;

	/**
	 * @var string
	 */
	static $_hostInfo	= null;

	/**
	* Return value from GET or POST or if value absent return default value
	*
	* @param string $name name of key in GET or POST array
	* @param mixed $def default value if value absent in GET or POST array
	* @param string $method where search value in POST (p) or GET (g) or both
	* @return mixed value from GET or POST array or default value
	*/
	public static function get($name, $def = '', $method = 'gp')
	{
		$method = strtolower($method);
		if (isset($_POST[$name]) && (stristr($method, 'p') !== false))
			return $_POST[$name];
		if (isset($_GET[$name]) && (stristr($method, 'g') !== false))
			return $_GET[$name];
		return $def;
	}


	/**
	* Set value to GET or POST array
	*
	* @param string $name name of key GET or POST array
	* @param mixed $value value for insert in GET or POST
	* @param string $method where insert value in POST (p) or GET (g)
	*/
	public static function set($name, $value, $method = 'g')
	{
		$method = strtolower($method);
		if ($method == 'p') $_POST[$name] = $value;
		else $_GET[$name] = $value;
	}


	/**
	* Function return action from GET
	*
	* @param string $def default action if action absent in GET array
	* @return string action
	*/
	public static function getAction($def = '')
	{
		$act = self::get("act", $def);
		if (is_array($act))
			$act = array_pop(array_keys($act));
		return $act;
	}


	/**
	* Function for forward
	*
	* @param string $url forward url
	* @param string $msg message for show after forward
	* @param string $err error for show after forward
	*/
	public static function forward($url = '', $msg = false, $err = false)
	{
		$aurl = parse_url ($url);
		$path = basename($aurl['path']);
		//if (empty($path))
			//$url = _cfg('script_name') . "?" . $aurl['query'].($aurl['fragment']? "#".$aurl['fragment'] : "");
		if ($msg)
			self::addMessage($msg);
		if ($err)
			self::addError($err);
		header("Location: $url");
		exit;
	}


	/**
	*  Reload page
	*/
	public static function reload()
	{
		self::forward($_SERVER['REQUEST_URI']);
	}


	/**
	* Return integer from GET or POST or if value absent return default value
	*
	* @param string $name name of key in GET or POST array
	* @param integer $def default value if value absent in GET or POST array
	* @param string $method where search value in POST (p) or GET (g) or both
	* @return integer value from GET or POST array or default value
	*/
	public static function getInt($name, $def = 0, $method = 'gp')
	{
		return intval(self::get($name, $def));
	}


	/**
	* Return array from GET or POST or if array absent return default array
	*
	* @param string $name name of key in GET or POST array
	* @param array $def default array if array absent in GET or POST array
	* @param string $method where search value in POST (p) or GET (g) or both
	* @return array value from GET or POST array or default array
	*/
	public static function getArray($name, $def = array(), $method = 'gp')
	{
		return (array)self::get($name, $def);
	}

	/**
	* Add message to session
	*
	* @param string $text message text
	*/
	public static function addMessage($text)
	{
		if (!isset($_SESSION['messages'])) $_SESSION['messages'] = array();
		$_SESSION['messages'][] = $text;
	}


	/**
	* Return all messages from session
	*
	* @param boolean $clear true - clear messages after get
	* @return array all messages
	*/
	public static function getMessages($clear = true)
	{
		$res = 	$_SESSION['messages'];
		if ($clear) $_SESSION['messages'] = array();
		return (array)$res;
	}


	/**
	* Add error to session
	*
	* @param string $text error text
	*/
	public static function addError($text)
	{
		if (!isset($_SESSION['errors'])) $_SESSION['errors'] = array();
		if (is_array($text)) $_SESSION['errors'] = array_merge($_SESSION['errors'], $text);
		else $_SESSION['errors'][] = $text;
	}


	/**
	* Return false if in session array error empty, else return true
	*
	* @return boolean has errors
	*/
	public static function hasErrors()
	{
		if (!isset($_SESSION['errors']) || sizeof($_SESSION['errors']) == 0)
			return false;
		return  true;
	}


	/**
	* Return all errors from session
	*
	* @param boolean $clear true - clear errors after get
	* @return array all errors
	*/
	public static function getErrors($clear = true)
	{
		$res = 	$_SESSION['errors'];
		if ($clear) $_SESSION['errors'] = array();
		return (array)$res;
	}

	/**
	 * Returns the path info of the currently requested URL.
	 * This refers to the part that is after the entry script and before the question mark.
	 * The starting and ending slashes are stripped off.
	 * @return string part of the request URL that is after the entry script and before the question mark.
	 */
	public static function getPathInfo()
	{
		if(self::$_pathInfo===null)
		{
			$pathInfo=self::getRequestUri();

			if(($pos=strpos($pathInfo,'?'))!==false)
				$pathInfo=substr($pathInfo,0,$pos);

			$pathInfo=self::decodePathInfo($pathInfo);

			$scriptUrl=self::getScriptUrl();
			$baseUrl=self::getBaseUrl();
			if(strpos($pathInfo,$scriptUrl)===0)
				$pathInfo=substr($pathInfo,strlen($scriptUrl));
			elseif($baseUrl==='' || strpos($pathInfo,$baseUrl)===0)
				$pathInfo=substr($pathInfo,strlen($baseUrl));
			elseif(strpos($_SERVER['PHP_SELF'],$scriptUrl)===0)
				$pathInfo=substr($_SERVER['PHP_SELF'],strlen($scriptUrl));
			self::$_pathInfo=trim($pathInfo,'/');
		}
		return self::$_pathInfo;
	}

	/**
	 * Returns the request URI portion for the currently requested URL.
	 * This refers to the portion that is after the {@link hostInfo host info} part.
	 * It includes the {@link queryString query string} part if any.
	 * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
	 * @return string the request URI portion for the currently requested URL.
	 */
	public static function getRequestUri()
	{
		if(self::$_requestUri===null)
		{
			if(isset($_SERVER['HTTP_X_REWRITE_URL'])) // IIS
				self::$_requestUri=$_SERVER['HTTP_X_REWRITE_URL'];
			elseif(isset($_SERVER['REQUEST_URI']))
			{
				self::$_requestUri=$_SERVER['REQUEST_URI'];
				if(!empty($_SERVER['HTTP_HOST']))
				{
					if(strpos(self::$_requestUri,$_SERVER['HTTP_HOST'])!==false)
						self::$_requestUri=preg_replace('/^\w+:\/\/[^\/]+/','',self::$_requestUri);
				}
				else
					$this->_requestUri=preg_replace('/^(http|https):\/\/[^\/]+/i','',self::$_requestUri);
			}
			elseif(isset($_SERVER['ORIG_PATH_INFO']))  // IIS 5.0 CGI
			{
				self::$_requestUri=$_SERVER['ORIG_PATH_INFO'];
				if(!empty($_SERVER['QUERY_STRING']))
					self::$_requestUri.='?'.$_SERVER['QUERY_STRING'];
			}
		}
		return self::$_requestUri;
	}


	/**
	 * Decodes the path info.
	 * This method is an improved variant of the native urldecode() function and used in {@link getPathInfo getPathInfo()} to
	 * decode the path part of the request URI. You may override this method to change the way the path info is being decoded.
	 * @param string $pathInfo encoded path info
	 * @return string decoded path info
	 */
	protected static function decodePathInfo($pathInfo)
	{
		$pathInfo = urldecode($pathInfo);

		// is it UTF-8?
		if(preg_match('%^(?:
		   [\x09\x0A\x0D\x20-\x7E]            # ASCII
		 | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
		 | \xE0[\xA0-\xBF][\x80-\xBF]         # excluding overlongs
		 | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
		 | \xED[\x80-\x9F][\x80-\xBF]         # excluding surrogates
		 | \xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3
		 | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
		 | \xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16
		)*$%xs', $pathInfo))
		{
			return $pathInfo;
		}
		else
		{
			return utf8_encode($pathInfo);
		}
	}


	/**
	 * Returns the relative URL of the entry script.
	 * The implementation of this method referenced Zend_Controller_Request_Http in Zend Framework.
	 * @return string the relative URL of the entry script.
	 */
	public static function getScriptUrl()
	{
		if(self::$_scriptUrl===null)
		{
			$scriptName=basename($_SERVER['SCRIPT_FILENAME']);
			if(basename($_SERVER['SCRIPT_NAME'])===$scriptName)
				self::$_scriptUrl=$_SERVER['SCRIPT_NAME'];
			elseif(basename($_SERVER['PHP_SELF'])===$scriptName)
				self::$_scriptUrl=$_SERVER['PHP_SELF'];
			elseif(isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME'])===$scriptName)
				self::$_scriptUrl=$_SERVER['ORIG_SCRIPT_NAME'];
			elseif(($pos=strpos($_SERVER['PHP_SELF'],'/'.$scriptName))!==false)
				self::$_scriptUrl=substr($_SERVER['SCRIPT_NAME'],0,$pos).'/'.$scriptName;
			elseif(isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'],$_SERVER['DOCUMENT_ROOT'])===0)
				self::$_scriptUrl=str_replace('\\','/',str_replace($_SERVER['DOCUMENT_ROOT'],'',$_SERVER['SCRIPT_FILENAME']));
		}
		return self::$_scriptUrl;
	}


	/**
	 * Returns the relative URL for the application.
	 * This is similar to {@link getScriptUrl scriptUrl} except that
	 * it does not have the script file name, and the ending slashes are stripped off.
	 * @param boolean $absolute whether to return an absolute URL. Defaults to false, meaning returning a relative one.
	 * @return string the relative URL for the application
	 * @see setScriptUrl
	 */
	public static function getBaseUrl($absolute=false)
	{
		if(self::$_baseUrl===null)
			self::$_baseUrl=rtrim(dirname(self::getScriptUrl()),'\\/');
		return $absolute ? self::getHostInfo() . self::$_baseUrl : self::$_baseUrl;
	}


	/**
	 * Returns the schema and host part of the application URL.
	 * The returned URL does not have an ending slash.
	 * By default this is determined based on the user request information.
	 * You may explicitly specify it by setting the {@link setHostInfo hostInfo} property.
	 * @param string $schema schema to use (e.g. http, https). If empty, the schema used for the current request will be used.
	 * @return string schema and hostname part (with port number if needed) of the request URL
	 * @see setHostInfo
	 */
	public static function getHostInfo($schema='')
	{
		if(self::$_hostInfo===null)
		{
			if($secure=$this->getIsSecureConnection())
				$http='https';
			else
				$http='http';
			if(isset($_SERVER['HTTP_HOST']))
				self::$_hostInfo=$http.'://'.$_SERVER['HTTP_HOST'];
			else
			{
				self::$_hostInfo=$http.'://'.$_SERVER['SERVER_NAME'];
				$port=$secure ? $this->getSecurePort() : $this->getPort();
				if(($port!==80 && !$secure) || ($port!==443 && $secure))
					self::$_hostInfo.=':'.$port;
			}
		}
	}


	/**
	 * Returns the request type, such as GET, POST, HEAD, PUT, DELETE.
	 * Request type can be manually set in POST requests with a parameter named _method. Useful
	 * for RESTful request from older browsers which do not support PUT or DELETE
	 * @return string request type, such as GET, POST, HEAD, PUT, DELETE.
	 */
	public static function getRequestType()
	{
		if(isset($_POST['_method']))
			return strtoupper($_POST['_method']);

		return strtoupper(isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'GET');
	}

	/**
	 * Returns whether this is an AJAX (XMLHttpRequest) request.
	 *
	 * @return boolean whether this is an AJAX (XMLHttpRequest) request.
	 */
	public static function isAjaxRequest()
	{
		return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';
	}
}